/*
 * Copyright 2024 LinQingYing. and contributors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * The use of this source code is governed by the Apache License 2.0,
 * which allows users to freely use, modify, and distribute the code,
 * provided they adhere to the terms of the license.
 *
 * The software is provided "as-is", and the authors are not responsible for
 * any damages or issues arising from its use.
 *
 */

package com.linqingying.cangjie.resolve.calls.model

import com.linqingying.cangjie.descriptors.ClassDescriptor
import com.linqingying.cangjie.descriptors.TypeAliasDescriptor
import com.linqingying.cangjie.name.Name
import com.linqingying.cangjie.resolve.calls.components.InferenceSession
import com.linqingying.cangjie.resolve.scopes.receivers.DetailedReceiver
import com.linqingying.cangjie.resolve.scopes.receivers.QualifierReceiver
import com.linqingying.cangjie.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo
import com.linqingying.cangjie.resolve.scopes.receivers.TransientReceiver
import com.linqingying.cangjie.types.UnwrappedType

interface ReceiverCangJieCallArgument : CangJieCallArgument {
    val receiver: DetailedReceiver
    val isSafeCall: Boolean
}

interface CollectionLiteralCangJieCallArgument : PostponableCangJieCallArgument

interface CangJieCallArgument {
    val isSpread: Boolean
    val argumentName: Name?
}

interface PostponableCangJieCallArgument : CangJieCallArgument, ResolutionAtom

interface SimpleCangJieCallArgument : CangJieCallArgument, ReceiverCangJieCallArgument {
    override val receiver: ReceiverValueWithSmartCastInfo
}

interface CallableReferenceCangJieCallArgument : PostponableCangJieCallArgument, CallableReferenceResolutionAtom {
    override val isSpread: Boolean
        get() = false



    override val call: CangJieCall
}

interface ExpressionCangJieCallArgument : SimpleCangJieCallArgument, ResolutionAtom


sealed class LHSResult {


    class Type(val qualifier: QualifierReceiver?, resolvedType: UnwrappedType) : LHSResult() {
        val unboundDetailedReceiver: ReceiverValueWithSmartCastInfo

        init {
            if (qualifier != null) {
                assert(qualifier.descriptor is ClassDescriptor || qualifier.descriptor is TypeAliasDescriptor) {
                    "Should be ClassDescriptor: ${qualifier.descriptor}"
                }
            }

            val unboundReceiver = TransientReceiver(resolvedType)
            unboundDetailedReceiver = ReceiverValueWithSmartCastInfo(unboundReceiver, emptySet(), isStable = true)
        }
    }

    class Expression(val lshCallArgument: SimpleCangJieCallArgument) : LHSResult()

    // todo this case is forbid for now
    object Empty : LHSResult()

    object Error : LHSResult()
}

interface SimpleTypeArgument : TypeArgument {
    val type: UnwrappedType
}

interface FunctionExpression : LambdaCangJieCallArgument {
    override val parametersTypes: Array<UnwrappedType?>

    // null means that there function can not have receiver
    val receiverType: UnwrappedType?

    val contextReceiversTypes: Array<UnwrappedType?>

    // null means that return type is not declared, for fun(){ ... } returnType == Unit
    val returnType: UnwrappedType?
}

interface SimpleCangJieArgument : CangJieCallArgument, ReceiverCangJieCallArgument {
    override val receiver: ReceiverValueWithSmartCastInfo
}

interface TypeArgument

// Used as a stub or underscored type argument
object TypeArgumentPlaceholder : TypeArgument
interface SubCangJieCallArgument : SimpleCangJieCallArgument, ResolutionAtom {
    val callResult: PartialCallResolutionResult
}

class QualifierReceiverCangJieCallArgument(override val receiver: QualifierReceiver) : ReceiverCangJieCallArgument {
    override val isSafeCall: Boolean
        get() = false // TODO: add warning

    override fun toString() = "$receiver"

    override val isSpread get() = false
    override val argumentName: Name? get() = null
}

interface LambdaCangJieCallArgument : PostponableCangJieCallArgument {
    override val isSpread: Boolean
        get() = false

    /*
     * Builder inference is supported only for lambdas (so it's implemented only in `LambdaCangJieArgumentImpl`),
     * anonymous functions aren't supported
     */
    var hasBuilderInferenceAnnotation: Boolean
        get() = false
        set(_) {}

    var builderInferenceSession: InferenceSession?
        get() = null
        set(_) {}

    /**
     * parametersTypes == null means, that there is no declared arguments
     * null inside array means that this type is not declared explicitly
     */
    val parametersTypes: Array<UnwrappedType?>?
}
